package com.hundsun.aitest.service.impl;

import cn.hutool.db.Entity;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.hundsun.aitest.model.ai.ChatRequest;
import com.hundsun.aitest.model.ai.Message;
import com.hundsun.aitest.model.ai.ParserScene;
import com.hundsun.aitest.model.plat.*;
import com.hundsun.aitest.service.DataBaseService;
import com.hundsun.aitest.service.TestInterfaceService;
import com.hundsun.aitest.service.YApiOperationService;
import com.hundsun.aitest.util.JsonContentExtractor;
import com.hundsun.aitest.util.YamlOperationUtils;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Service
@Slf4j
@Setter
public class TestInterfaceServiceImpl implements TestInterfaceService {

    @Autowired
    private LargeModelServiceImpl largeModelServiceImpl;
    
    @Autowired
    private YApiOperationService yApiOperationService;

    @Autowired
    private DataBaseService dataBaseService;

    private String project = "aml5";

    private boolean isLogin = false;

    /**反洗钱公共的参数字典，首次加载读取，只记录一次。销售商，TA列表，客户类型等等**/
    private Map<String, List<ParamsDict>> amlCommonParamsDict = new HashMap<>();


    /**
     * 登录yApi平台，获取接口服务列表
     * @return
     */
    private List<String> getInterfaceList() {
        yApiOperationService.setInitParams(this.project);
        yApiOperationService.loginPlat();         // 登录，获取cookie
        this.isLogin = true;
        yApiOperationService.getCatList();
        return yApiOperationService.getInterfaceList();
    }

    private String getAiQuestion(String yamlPath, Map<String, Object> inputData) throws JsonProcessingException {
        List<String> prompts = YamlOperationUtils.getPromptQuestion(yamlPath, inputData);
        // 调用大模型接口,获取接口描述
        AtomicReference<String> response = new AtomicReference<>("");
        prompts.forEach((prompt) -> {
            ChatRequest request = new ChatRequest();
            request.setMessages(Arrays.asList(new Message("user", prompt)));
            try {
                response.set(largeModelServiceImpl.sendRequest(request));
                log.info("执行Prompt提问的结果：" + response.get());
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        });
        // 读取接口信息
        String expectResult = largeModelServiceImpl.parseResponse(response.get());
        log.info("接口信息: {}", expectResult);
        return expectResult;
    }

    @Override
    public InterfaceDict patternInterface(String testPoint, boolean isGetDetail) throws JsonProcessingException {
        // 读取接口列表
        String yamlPath = "prompt/PatternInterfaceModule.yaml";
        List<String> interfaceList = this.getInterfaceList();
        Map<String, Object> inputDataOne = new HashMap<>();
        inputDataOne.put("testPoint", testPoint);
        inputDataOne.put("interfaceList", interfaceList);
        String expectResult = getAiQuestion(yamlPath, inputDataOne);
        InterfaceDict interfaceDict = new InterfaceDict();
        interfaceDict.setTestPoint(testPoint);
        if(expectResult != null) {
            String[] interfaceName = expectResult.split("interfaceName=");
            String[] interfaceParams = interfaceName[1].split("&");
            interfaceDict.setInterfaceName(interfaceParams[1]);
            interfaceDict.setInterfaceId(Integer.parseInt(interfaceParams[0]));
        }else{
            interfaceDict.setInterfaceName(null);
            interfaceDict.setInterfaceId(null);
        }
        log.info("返回匹配的接口信息: {}", interfaceDict);
        if(isGetDetail){
            interfaceDict = this.queryInterfaceDetail(interfaceDict.getInterfaceId());
        }
        return interfaceDict;
    }

    private List<ApiParams> parserParams(String params){
        List<ApiParams> result = new ArrayList<>();
        Map paramsMap = JSON.parseObject(params, Map.class);
        if(paramsMap != null && paramsMap.get("properties") != null) {
            Map properties = (Map) paramsMap.get("properties");
            List<String> required = (List<String>) paramsMap.get("required");
            properties.forEach((key, value) -> {
                ApiParams apiParams = new ApiParams();
                apiParams.setName((String) key);
                apiParams.setType((String) ((Map) value).get("type"));
                apiParams.setRequired(required.contains(apiParams.getName()) ? "true" : "false");
                apiParams.setDescription((String) ((Map) value).get("description"));
                apiParams.setPath("/" + key);
                result.add(apiParams);
            });
            log.info("parserParams: {}", result);
        }
        return result;
    }

    private List<ApiParams> parserFormParams(List<Map<String, String>> params) {
        List<ApiParams> result = new ArrayList<>();
        params.forEach(unit -> {
            ApiParams apiParams = new ApiParams();
            apiParams.setName(unit.get("name"));
            apiParams.setType(unit.get("type"));
            apiParams.setRequired(unit.get("required") == "1" ? "true" : "false");
            apiParams.setDescription(unit.get("desc"));
            apiParams.setPath("/" + unit.get("name"));
            result.add(apiParams);
        });
        log.info("parserFormParams: {}", result);
        return result;
    }

    /**
     * 解析返回参数，递归提取，记录参数路径
     * @param paramsMap：返回参数
     * @param result：解析结果
     * @param pathList ： 路径记录列表
     * @return
     */
    private List<ApiParams> parserResponseParams(Map paramsMap, List<ApiParams> result, List<String> pathList){
        Map properties = (Map) paramsMap.get("properties");
        if(properties != null) {
            int level = pathList.size();
            properties.forEach((key, value) -> {
                ApiParams apiParams = new ApiParams();
                apiParams.setName((String) key);
                apiParams.setType((String) ((Map) value).get("type"));
                apiParams.setRequired("false");
                if (((Map<?, ?>) value).get("description") != null) {
                    apiParams.setDescription((String) ((Map) value).get("description"));
                }
                if(pathList.isEmpty()){
                    pathList.add(key.toString());
                }
                if(level == 0){
                    pathList.set(0, key.toString());
                }else{
                    pathList.set(level-1, key.toString());
                }
                apiParams.setPath("/" + String.join("/", pathList));
                result.add(apiParams);
                if (((Map<?, ?>) value).get("properties") != null) {
                    pathList.add("1");
                    this.parserResponseParams((Map) value, result, pathList);
                    pathList.remove(pathList.size()-1); // 递归回溯
                }
                if (((Map<?, ?>) value).containsKey("items")) {
                    pathList.add("0");
                    pathList.add("1");
                    this.parserResponseParams((Map) ((Map<?, ?>) value).get("items"), result, pathList);
                    pathList.remove(pathList.size()-1);  // 递归回溯
                    pathList.remove(pathList.size()-1);  // 递归回溯
                }
            });
            log.info("parserParams: {}", result);
        }
        return result;
    }

    private ApiParams queryFormatterDict(List<ApiParams> paramsList){
        ApiParams formatterParams = new ApiParams();
        formatterParams.setName("formatter(Object)");
        JSONObject jsonObject = new JSONObject();
        paramsList.forEach(apiParams -> {
            String nameKey = apiParams.getName();
            String desc = apiParams.getDescription();
            if(desc != null) {
                // 添加字典类
                Pattern pattern = Pattern.compile("(B\\d{4})");
                Matcher matcher = pattern.matcher(desc);
                if (matcher.find()) {
                    String formatter = matcher.group(1);

                    String secondKey = nameKey.replace("_desc", "");
                    jsonObject.put(nameKey, "dict(" + formatter + "):" + secondKey);
                }
                // 添加日期类
//                Pattern pattern2 = Pattern.compile("amlDate(/):");
//                Matcher matcher2 = pattern2.matcher(desc);
//                if (matcher2.find()) {
//                    jsonObject.put(nameKey, desc);
//                }
            }
        });
        log.debug("queryFormatterDict: {}", jsonObject);
        if(!jsonObject.isEmpty()){
            formatterParams.setType("String");
            formatterParams.setRequired("true");
            formatterParams.setDefaultValue(jsonObject.toJSONString());
        }else{
            formatterParams.setRequired("false");
        }
        return formatterParams;
    }

    private Map<String, String> parserHeaders(List<Map<String, Object>> headers) {
        Map<String, String> result = new HashMap<>();
        headers.forEach((header) ->{
            if(header.get("required").equals("1")){
                result.put((String) header.get("name"), header.get("value").toString());
            }
        });
        log.info("parserHeaders:{}", result);
        return result;
    }


    @Override
    public InterfaceDict queryInterfaceDetail(Integer interfaceId) {
        if(!this.isLogin){
            this.getInterfaceList();
        }
        InterfaceDict interfaceDict = new InterfaceDict();
        yApiOperationService.loginPlat();         // 登录，获取cookie
        JSONObject interfaceInfo = yApiOperationService.getInterfaceParams(interfaceId);
        log.info("接口详情: {}", interfaceInfo);
        Map<String, String> headers = null;
        if(interfaceInfo != null){
            List<Map<String, Object>> requestHeaders = (List<Map<String, Object>>) interfaceInfo.get("req_headers");
            headers = this.parserHeaders(requestHeaders);
        }
        // 解析接口信息
        String requestType = null;
        List<ApiParams> paramsList = null;
        List<ApiParams> responseList = null;
        if(interfaceInfo != null && interfaceInfo.containsKey("req_body_type")){
            requestType = interfaceInfo.get("req_body_type").toString();

            if (requestType.equals("form")) {
                List<Map<String, String>> paramsFrom = (List<Map<String, String>>) interfaceInfo.get("req_body_form");
                paramsList = this.parserFormParams(paramsFrom);
            } else {
                paramsList = this.parserParams((String) interfaceInfo.get("req_body_other"));
            }
            List<ApiParams> result = new ArrayList<>();
            List<String> pathList = new ArrayList<>();
            Map paramsMap = JSON.parseObject((String) interfaceInfo.get("res_body"), Map.class);
            responseList = this.parserResponseParams(paramsMap, result, pathList);
            // 判断返回列表中是否存在字典项？赋值给formatter={k:v},required=true
            ApiParams formatterParams = this.queryFormatterDict(responseList);
            if(formatterParams.getRequired().equals("true")){
//                paramsList.add(formatterParams);
                interfaceDict.setReqFormatter(formatterParams);
            }
        }
        // 设置接口信息，作为返回结果
        String title = interfaceInfo.get("title").toString();
        interfaceDict.setInterfaceId(interfaceId);
        interfaceDict.setScriptName(interfaceId + "_" + title.replace(" ", "_"));
        interfaceDict.setUrl((String) interfaceInfo.get("path"));
        interfaceDict.setDescription((String) interfaceInfo.get("desc"));
        interfaceDict.setBodyType(requestType);
        interfaceDict.setMethod((String) interfaceInfo.get("method"));
        interfaceDict.setHeaders(headers);
        interfaceDict.setParamsList(paramsList);
        interfaceDict.setResponseParamsList(responseList);
        interfaceDict.setResponseBody(interfaceInfo.get("res_body").toString());
        log.info("Interface detail: {}", interfaceDict);
        return interfaceDict;
    }

    @Override
    public List<ParserScene> standardTestParseContent(String parseContent) throws JsonProcessingException {
        // 读取接口列表
        String yamlPath = "prompt/TestPointStandard.yaml";
        Map<String, Object> inputDataOne = new HashMap<>();
        inputDataOne.put("parseContent", parseContent);
        String expectResult = getAiQuestion(yamlPath, inputDataOne);
        List<Map<String, String>> expectList = JsonContentExtractor.extractContentToList(expectResult);
        List<ParserScene> result = new ArrayList<>();
        if(expectList != null){
            expectList.forEach(expect -> {
                ParserScene parserScene = new ParserScene();
                parserScene.setTestPoint(expect.get("testPoint"));
                parserScene.setScenes(expect.get("scenes"));
                result.add(parserScene);
            });
        }
        return result;
    }

    /**
     * 赛题示例接口，字典表和基础数据读取逻辑
     * @return Map<String, List<ParamsDict>> ： key为字典表名称，value为字典表数据定义。
     */
    private Map<String, List<ParamsDict>> readLocalDict(){
        Map<String, Object> content = YamlOperationUtils.readYaml("prompt/BasicDict.yaml");
        Map<String, List<ParamsDict>> paramsDictMap = new HashMap<>();
        List<Map<String, Object>> basicDictList = (List<Map<String, Object>>) content.get("dict");
        basicDictList.forEach(basicDict -> {
            String key = (String) basicDict.get("key");
            List<ParamsDict> paramsDictList = (List<ParamsDict>) basicDict.get("data");
            paramsDictMap.put(key.toUpperCase(), paramsDictList);
        });
        List<Map<String, Object>> basicDataList = (List<Map<String, Object>>) content.get("data");
        basicDataList.forEach(basicData -> {
            String key = (String) basicData.get("key");
            List<ParamsDict> paramsDictList = new ArrayList<>();
            ParamsDict paramsDict = new ParamsDict();
            paramsDict.setComment((String) basicData.get("comment"));
            paramsDict.setValue(basicData.get("value").toString());
            paramsDict.setKey(key);
            paramsDictList.add(paramsDict);
            paramsDictMap.put(key.toUpperCase(), paramsDictList);
        });
        log.info("read dict : {}", paramsDictMap);
        return paramsDictMap;
    }

    /**
     * 读取字典表
     * @param field ： 字段名称
     * @param sql ： 查询sql，必须有 select xx as key, xx as value, xx as comment from xxx.xxx where 1=1 limit 40;
     * @return : 字段项目
     */
    private Map<String, List<ParamsDict>> readAmlDict(String field, String sql){
        log.info("act sql : {}", sql);
        Map<String, List<ParamsDict>> paramsDictMap = new HashMap<>();
        List<ParamsDict> paramsDictList = new ArrayList<>();
        List<Entity> dataRows = dataBaseService.actSql(sql);
        AtomicInteger index = new AtomicInteger();
        dataRows.forEach(dataRow -> {
            index.addAndGet(1);
            Set<String> fileNames = dataRow.getFieldNames();
            if(!fileNames.isEmpty()){
                ParamsDict paramsDict = new ParamsDict();
                paramsDict.setKey(field + "|" + dataRow.get("name", ""));
                paramsDict.setValue(dataRow.get("value", ""));
                paramsDict.setComment("No." + index + "值含义:" + dataRow.get("comment", ""));
                paramsDictList.add(paramsDict);
            }
        });
        paramsDictMap.put(field.toUpperCase(), paramsDictList);
        log.info("aml {} dict : {}", field, paramsDictList);
        return paramsDictMap;
    }

    private void readAmlBasicDict(){
        if(amlCommonParamsDict.isEmpty()){
            Map<String, String> amlFiledNames = new HashMap<>();
            // 添加销售商字典
            amlFiledNames.put("agency_no", "select t.agency_english_name as name, t.agency_no as value, t.agency_name as comment  from hsfund.fnd_agency t where 1=1 limit 40");
            // 添加销售商字典
            amlFiledNames.put("ta_no", "select 'TA_NO' as name, t.ta_no as value, 'TA_NO' as comment  from hsfund.fnd_tainfo t where 1=1 limit 40");
            // 添加客户字典
            amlFiledNames.put("product_code", "select '' as name, t.product_code as value, t.product_name as comment  from hsfund.fnd_fund_info t where 1=1 limit 40");
            // 查询字典列表
            amlFiledNames.forEach((filed, sql) -> {
                Map<String, List<ParamsDict>> agencyMap = this.readAmlDict(filed, sql);
                amlCommonParamsDict.putAll(agencyMap);
            });
            // 添加客户类型
            List<ParamsDict> paramsDictList = new ArrayList<>();
            ParamsDict paramsDict = new ParamsDict();
            paramsDict.setKey("client_type|01");
            paramsDict.setValue("01");
            paramsDict.setComment("个人");
            paramsDictList.add(paramsDict);
            paramsDict.setKey("client_type|02");
            paramsDict.setValue("02");
            paramsDict.setKey("机构");
            paramsDictList.add(paramsDict);
            paramsDict.setKey("client_type|03");
            paramsDict.setValue("03");
            paramsDict.setKey("产品");
            paramsDictList.add(paramsDict);
            amlCommonParamsDict.put("client_type".toUpperCase(), paramsDictList);
            log.info("aml basic dict : {}", amlCommonParamsDict);
        }
    }

    /**
     * 读取aml的PBS的字典表
     * @param interfaceDict ： 字典名称
     * @return
     */
    private InterfaceDict readAmlPBSDict(InterfaceDict interfaceDict){
        List<ApiParams> paramsList = interfaceDict.getParamsList();
        paramsList.forEach(apiParams -> {
            String field = apiParams.getName();
            String desc = apiParams.getDescription();
            Pattern pattern = Pattern.compile("(B\\d{4})");
            boolean isCommonDict = true;
            if(desc!= null && !desc.isEmpty()){
                Matcher matcher = pattern.matcher(desc);
                if(matcher.find()){
                    String dictEntry = matcher.group(1);
                    String sql = "select t.dict_entry as name, t.sub_entry as value, t.dict_prompt as comment  from hspbs.pbs_dictionary t " +
                            "where t.dict_entry = '" + dictEntry + "' and t.is_enabled =1 limit 40";
                    Map<String, List<ParamsDict>> paramsDictMap = this.readAmlDict(field, sql);
                    apiParams.setExample(paramsDictMap.get(field.toUpperCase()));
                    isCommonDict = false;
                }
            }
            // 查询通用字典表，是否存在
            List<ParamsDict> paramsDictList = amlCommonParamsDict.get(field.toUpperCase());
            if(isCommonDict && paramsDictList != null){
                apiParams.setExample(paramsDictList);
            }
        });
        return interfaceDict;
    }

    @Override
    public InterfaceDict queryParamsDict(String project, InterfaceDict interfaceDict) {
        InterfaceDict interfaceDictResult = null;
        if(project.toLowerCase().startsWith("aml")){
            log.info("query aml basic data and dict !");
            this.readAmlBasicDict();
            interfaceDictResult = this.readAmlPBSDict(interfaceDict);
            interfaceDictResult.setCommonParamsDict(amlCommonParamsDict);
            // 读取表结构
            List<TableInformation> tableStructs = this.queryTableStructs(interfaceDict.getDescription());
            interfaceDictResult.setTableStructures(tableStructs);
        }else if(project.toLowerCase().startsWith("urp")){
            log.info("query urp basic data and dict !");
            interfaceDictResult = interfaceDict;
        }else {
            Map<String, List<ParamsDict>> paramsDictMap = this.readLocalDict();
            log.info("query dict : {}", paramsDictMap);
            if(!paramsDictMap.isEmpty()) {
                List<ApiParams> paramsList = interfaceDict.getParamsList();
                paramsList.forEach(apiParams -> {
                    String rawKey = apiParams.getName();
                    List<ParamsDict> paramsDictList = paramsDictMap.get(rawKey.toUpperCase());
                    if(paramsDictList != null) {
                        apiParams.setExample(paramsDictList);
                    }
                });
                interfaceDictResult = interfaceDict;
            }
        }
        return interfaceDictResult;
    }

    /**
     * 解析html获取表名
     * @param htmlString : "涉及的表：hsfund.fnd_client_offline，hsfund.fnd_client_online_1, hspbs.fnd_client_online_3"
     * @return
     */
    private List<String> parserHtmlAndGetTableNames(String htmlString){
        // 解析HTML字符串
        Document doc = Jsoup.parse(htmlString);
        // 提取所有文本内容
        String text = doc.text();
        Pattern pattern = Pattern.compile("([a-zA-Z]+\\.[a-zA-Z0-9_]+)");
        Matcher matcher = pattern.matcher(text);
        // 存储匹配结果的列表
        List<String> tableNames = new ArrayList<>();
        while (matcher.find()) {
            String tableName = matcher.group(1);
            tableNames.add(tableName);
        }
        log.info("table names : {}", tableNames);
        return tableNames;
    }

    @Override
    public List<TableInformation> queryTableStructs(String htmlString){
        List<String> tableNames = this.parserHtmlAndGetTableNames(htmlString);
        if(tableNames.isEmpty()){
            return null;
        }
        List<TableInformation> tables = new ArrayList<>();
        for(String tableName : tableNames){
            TableInformation tableInformation = new TableInformation();
            List<TableStruct> tableStructs = dataBaseService.readTableStructure(tableName);
            tableInformation.setTableName(tableName);
            tableInformation.setTableStructure(tableStructs);
            JSONObject dataExample = new JSONObject();
            tableStructs.forEach((unit)-> {
                dataExample.put(unit.getName(), unit.getDefaultValue());
                tableInformation.setDataExample(dataExample.toJSONString());
            });
            tables.add(tableInformation);
        }
        log.info("table struct : {}", tables);
        return tables;
    }
}
